﻿namespace Raven
{
    public class GoalTraverseEdge : Goal<RavenBot>
    {
        //the edge the bot will follow
        private PathEdge  _edge;

        //true if m_Edge is the last in the path.
        private  bool      _lastEdgeInPath;

        //the estimated time the bot should take to traverse the edge
        private Fix     _timeExpected;
  
        //this records the time this goal was activated
        private Fix     _startTime;

        //returns true if the bot gets stuck
        private bool isStuck()
        {
            Fix TimeTaken = _owner.GetWorld().GetTimer().currentTime - _startTime;

            if (TimeTaken > _timeExpected)
            {
                Logger.Log("BOT " + _owner.ID() + " IS STUCK!!");

                return true;
            }

            return false;
        }
            
        public GoalTraverseEdge(RavenBot owner, PathEdge edge, bool lastEdge) : base(owner, GoalType.goal_traverse_edge)
        {
            _edge = edge;
            _timeExpected = 0;
            _lastEdgeInPath = lastEdge;
        }

        public override void Activate()
        {
            _status = GoalStatus.active;
  
            // //the edge behavior flag may specify a type of movement that necessitates a 
            // //change in the bot's max possible speed as it follows this edge
            // switch(m_Edge.Behavior())
            // {
            //     case NavGraphEdge::swim:
            //     {
            //         m_pOwner->SetMaxSpeed(script->GetDouble("Bot_MaxSwimmingSpeed"));
            //     }
            //
            //         break;
            //
            //     case NavGraphEdge::crawl:
            //     {
            //         m_pOwner->SetMaxSpeed(script->GetDouble("Bot_MaxCrawlingSpeed"));
            //     }
            //
            //         break;
            // }
  

            //record the time the bot starts this goal
            _startTime = _owner.GetWorld().GetTimer().currentTime;
  
            //calculate the expected time required to reach the this waypoint. This value
            //is used to determine if the bot becomes stuck 
            _timeExpected = _owner.CalculateTimeToReachPosition(_edge.Destination());
  
            //factor in a margin of error for any reactive behavior
            Fix MarginOfError = 2;

            _timeExpected += MarginOfError;


            //set the steering target
            _owner.GetSteering().SetTarget(_edge.Destination());

            //Set the appropriate steering behavior. If this is the last edge in the path
            //the bot should arrive at the position it points to, else it should seek
            if (_lastEdgeInPath)
            {
                _owner.GetSteering().ArriveOn();
            }

            else
            {
                _owner.GetSteering().SeekOn();
            }
        }

        public override GoalStatus Process()
        {
            //if status is inactive, call Activate()
            ActivateIfInactive();
  
            //if the bot has become stuck return failure
            if (isStuck())
            {
                _status = GoalStatus.failed;
            }
  
            //if the bot has reached the end of the edge return completed
            else
            { 
                if (_owner.isAtPosition(_edge.Destination()))
                {
                    _status = GoalStatus.completed;
                }
            }

            return _status;
        }

        public override void Terminate()
        {
            //turn off steering behaviors.
            _owner.GetSteering().SeekOff();
            _owner.GetSteering().ArriveOff();

            //return max speed back to normal
            _owner.SetMaxSpeed(Constants.Bot_MaxSpeed);
        }
    }
}